/** 由 HTML DOM -> VNode: 将这个函数当做 compiler 函数 */
function getVNode( node ) {
  const nodeType = node.nodeType
  let _node = null
  if (nodeType === 1) { // 元素节点
    const nodeName = node.nodeName // 获取元素标签
    const attrs = node.attributes // 获取元素属性 伪数组
    const objAttrs = {}
    // 循环
    for (let i = 0;  i < attrs.length; i++) {
      objAttrs[attrs[i].nodeName] = attrs[i].nodeValue
    }
    _node = new VNode(nodeName, objAttrs, undefined, nodeType)
    // 节点下面还有节点
    const childNode = node.childNodes
    for ( let i = 0; i < childNode.length; i++ ) {
      _node.appendChild( getVNode(childNode[i]) ) // 递归
    }
  } else if (nodeType === 3){ // 文本节点
    _node = new VNode(undefined, undefined, node.textContent, nodeType)
  }
  return _node
}

function getValueByPath(data, value) {
  let arr = value.split('.')
  let res = data
  let prop
  while( prop = arr.shift() ) {
    res = res[prop]
  }
  return res
}
const regMustache = /\{\{\s*(\S+)\s*\}\}/
/** 将带有坑的Vnode与数据 data 结合, 得到 填充数据的 VNode: 模拟 AST -> VNode */
function compile (vnode, _data) {
  const data = vnode.data
  let value = vnode.value
  const type = vnode.type
  const children = vnode.children
  const tag = vnode.tag

  let _vnode = null
  if (type === 3) { // 文本节点
    value = value.replace(regMustache, function (node, val) {
      return getValueByPath( _data, val)
    })
    _vnode = new VNode( tag, data, value, type )
  } else if (type === 1) { // 元素节点
    _vnode = new VNode(tag, data, value, type)
    children.forEach(child => {
      _vnode.appendChild(compile(child, _data))
    })
  }
  return _vnode
}
 // 将 vNode 转换为真正的 DOM
function parseVNode( vnode ) {
  const nodeType = vnode.type
  let _node = null;
  if (nodeType === 3) { // 是文本
    return document.createTextNode(vnode.value)
  } else if (nodeType === 1) {// 是节点
    _node = document.createElement(vnode.tag)
    // 获取节点属性
    const data = vnode.data
    Object.keys(data).forEach(key => {
      const attrValue = data[key]
      _node.setAttribute(key , attrValue)
    })
    const children = vnode.children
    children.forEach(subvnode => {
      _node.appendChild( parseVNode( subvnode ) )
    })
    return _node
  }
}